package com.example.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.constant.MessageConstant;
import com.example.context.BaseContext;
import com.example.dto.CommentDTO;
import com.example.dto.PageDTO;
import com.example.entity.Comment;
import com.example.entity.Novel;
import com.example.mapper.CommentMapper;
import com.example.query.CommentQuery;
import com.example.result.Result;
import com.example.service.ICommentService;
import com.example.service.INovelService;
import com.example.vo.CommentVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
@RequiredArgsConstructor
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements ICommentService {

    private final INovelService novelService;


    /*
    * 添加评论
    * @param commentDTO
    * @return
    * */
    @Override
    public void addComment(CommentDTO commentDTO) {
        //评论内容不能为空
        String content = commentDTO.getContent();
        Integer rating = commentDTO.getRating();
        if(content.length() == 0 || content == null || rating == 0){
            throw new RuntimeException(MessageConstant.COMMENT_CONTENT_NOT_NULL);
        }
        //判断用户是否已经评论
        Long userId = BaseContext.getCurrentId();
        Long novelId = commentDTO.getNovelId();
        Long count = lambdaQuery()
                .eq(Comment::getNovelId, novelId)
                .eq(Comment::getUserId, userId)
                .eq(Comment::getStatus, 1)
                .count();
        if(count > 0){
            throw new RuntimeException(MessageConstant.USER_HAS_COMMENTED);
        }
        //更新小说评分和评论数
        updateNovelInfo(rating,1, novelId);
        //把用户评分和评论内容保存到数据库中
        Comment comment = Comment.builder()
                .novelId(commentDTO.getNovelId())
                .userId(userId)
                .userName(commentDTO.getUserName())
                .content(commentDTO.getContent())
                .rating(commentDTO.getRating())
                .status(1)
                .build();
        save(comment);
    }



    /*
    * 分页查询评论
    * @param commentQuery
    * @return
    * */
    @Override
    public Result<PageDTO<CommentVO>> QueryCommentpage(CommentQuery commentQuery) {
        Long novelId = commentQuery.getNovelId();
        Long userId = commentQuery.getUserId();
        //构造分页对象
        Page<Comment> page = commentQuery.toMpPage("create_time");
        //构造查询条件
        Page<Comment> p = lambdaQuery()
                .eq(novelId != null, Comment::getNovelId, novelId)
                .eq(userId != null, Comment::getUserId, userId)
                .eq(Comment::getStatus, 1)
                .page(page);
        //转换为VO
        PageDTO<CommentVO> pageDTO = PageDTO.of(p, CommentVO.class);
        return Result.success(pageDTO);
    }

    /*
    * 删除评论
    * @param id
    * @return
    * */
    @Override
    public void removeComment(Long id) {
        //获取评论信息
        Comment comment = getById(id);
        Integer rating = -comment.getRating();
        Long novelId = comment.getNovelId();
        //更新小说评分和评论数
        updateNovelInfo(rating, -1, novelId);
        //删除评论
        removeById(id);
    }

    /*
    * 更新小说评分和评论数
    * @param novelId
    * @return
    * */
    private void updateNovelInfo(Integer changeRating,Integer changeCommentCount, Long novelId) {
        //判断小说是否存在
        Novel novel = novelService.getById(novelId);
        if (novel == null) {
            throw new RuntimeException(MessageConstant.NOVEL_NOT_FOUND);
        }
        //计算新的评分和评论数
        Integer newTotalScore = changeRating + novel.getTotalScore();
        Integer newCommentCount = novel.getCommentCount() + changeCommentCount;
        // 使用 BigDecimal 进行精确计算并保留两位小数
        BigDecimal newTotalScoreBD = BigDecimal.valueOf(newTotalScore);
        BigDecimal newCommentCountBD = BigDecimal.valueOf(newCommentCount);
        BigDecimal newRatingBD = newTotalScoreBD.divide(newCommentCountBD, 2, RoundingMode.HALF_UP);
        double newRating = newRatingBD.doubleValue();
        novelService.lambdaUpdate()
                .eq(Novel::getId, novelId)
                .set(Novel::getCommentCount, newCommentCount)
                .set(Novel::getTotalScore, newTotalScore)
                .set(Novel::getRating, newRating)
                .update();
    }
}
